-- Matías Blanco & Sergio Pérez
-- Cruces. Práctica 3 - Tipos Protegidos en Ada - Parte (C)

with Ada.Text_IO,Ada.Numerics.Discrete_Random;
use Ada.Text_IO;

procedure CrucesTProtAda_C is

   subtype valores is Natural range 1..4;

   package NumeroAleatorio is new Ada.Numerics.Discrete_Random(valores);
   G: NumeroAleatorio.Generator;

   MAX_TIEMPO_CIRCULA: constant Integer := 3;
   MAX_TIEMPO_CRUZA: constant Integer := 2;
   TIEMPO_RELOJ_CAMBIO: constant Duration := 10.0;
   MAX_COCHES: constant Integer := 10;

   task Alarma;

   protected type TCruce is
      entry Pasar-Izq-Dere(id: Integer);
      entry Pasar-Dere-Izq(id: Integer);
      entry Pasar-Arriba-Abajo(id: Integer);
      entry Pasar-Abajo-Arriba(id: Integer);
      procedure Cambio;
      procedure Init;

   private
      --signals(1): boolean; ID
      --signals(2): boolean; DI
      --signals(3): boolean; AB
      --signals(4): boolean; BA
	signals : Array 1..4 of Boolean;

   end TCruce;

   task type Coche(id: Integer; vel: Integer; direccion: Integer);

   --Declaraciones de Cuerpos

   protected body TCruce is

      entry Pasar-Izq-Dere(id: Integer) when signals(1) is
      begin
         Put_Line("(***) El coche"&Integer'Image(id)&" esta cruzando de izquierda a derecha");
      end Pasar-Izq-Dere;

      entry Pasar-Dere-Izq(id: Integer) when signals(2) is
      begin
         Put_Line("(***) El coche"&Integer'Image(id)&" esta cruzando de derecha a izquierda");
      end Pasar-Dere-Izq;

      entry Pasar-Arriba-Abajo(id: Integer) when signals(3) is
      begin
         Put_Line("(***) El coche"&Integer'Image(id)&" esta cruzando de arriba hacia abajo");
      end Pasar-Arriba-Abajo;

      entry Pasar-Abajo-Arriba(id: Integer) when signals(4) is
      begin
         Put_Line("(***) El coche"&Integer'Image(id)&" esta cruzando de abajo hacia arriba");
      end Pasar-Abajo-Arriba;

      procedure cambio is
      begin
         signals(1) := not signals(1);
         signals(2) := not signals(2);
         signals(3) := not signals(3);
         signals(4) := not signals(4);
         New_Line;
         Put_Line("Las signals han cambiado:");
         if signals(1) and signals(2) then
            Put_Line("signal de izquierda-derecha: PASA");
            Put_Line("signal de derecha-izquierda: PASA");
            Put_Line("signal de arriba-abajo: STOP!");
            Put_Line("signal de abajo-arriba: STOP!");
         elsif signals(3) and signals(4) then
            Put_Line("signal de izquierda-derecha: STOP!");
            Put_Line("signal de derecha-izquierda: STOP!");
            Put_Line("signal de arriba-abajo: PASA");
            Put_Line("signal de abajo-arriba: PASA");
         end if;
         New_Line;
      end cambio;

      procedure Init is
      begin
         if NumeroAleatorio.Random(G)<=2 then
            signals(1) := true;
            signals(2) := true;
            signals(3) := false;
            signals(4) := false;
         else
            signals(1) := false;
            signals(2) := false;
            signals(3) := true;
            signals(4) := true;
         end if;
      end Init;
   end TCruce;

   Cruce: TCruce;

   task body Alarma is

   begin
      loop
         delay TIEMPO_RELOJ_CAMBIO;
         Cruce.cambio;
      end loop;
   end Alarma;

   task body Coche is

   begin
      t_delay = MAX_TIEMPO_CRUZA;

      if direccion=1 then
         Put_Line("(***) El coche"&Integer'Image(id)&" esta llegando al cruce por la izquierda");
         delay Duration(t_delay);
         Cruce.Pasar-Izq-Dere(id);
      elsif direccion=2 then
         Put_Line("(***) El coche"&Integer'Image(id)&" esta llegando al cruce por la derecha");
         delay Duration(t_delay);
         Cruce.Pasar-Dere-Izq(id);
      elsif direccion=3 then
         Put_Line("(***) El coche"&Integer'Image(id)&" esta llegando al cruce por arriba");
         delay Duration(t_delay);
         Cruce.Pasar-Arriba-Abajo(id);
      elsif direccion=4 then
         Put_Line("(***) El coche"&Integer'Image(id)&" esta llegando al cruce por abajo");
         delay Duration(t_delay);
         Cruce.Pasar-Abajo-Arriba(id);
      end if;
      delay Duration(tiempoCruzando);
      Put_Line("(***) El coche"&Integer'Image(id)&" ha terminado de cruzar");
   end Coche;

   type PCoche is access Coche;
   TCoche: PCoche;

begin

   Put_Line("Problema de los cruces dobles");New_Line;

   NumeroAleatorio.Reset(G);
   Cruce.Init;

   for i in 1..MAX_COCHES loop
      v := vAleatoria.Random(H);
      d := NumeroAleatorio.Random(G);
      TCoche := new Coche(i,v,d);
      delay Duration(NumeroAleatorio.Random(G));
   end loop;

end CrucesTProtAda_C;
